#ifndef NNE_DEVICE_CONV_PATH_H_
#define NNE_DEVICE_CONV_PATH_H_

#include "mem/dram.h"
#include "mem/sram.h"
#include "type.h"
#include "util.h"
#include <memory>
#include <cstring>

class Lut;

class ConvPath {
public:
  ConvPath(std::shared_ptr<MemInterface> In, std::shared_ptr<MemInterface> Out);
  bool irq_status;
  bool irq_mask;
  u32 debug_reg0;
  bool cvnn_start;
  u32 kernel_stride;
  u32 fc_detail;
  u32 ifm_width;
  u32 ifm_line_stride;
  u32 ifm_height;
  u32 ofm_width;
  u32 ofm_height;
  u32 ifm_num;
  u32 ofm_num;
  u32 fc_input_size;
  u32 fc_output_size;
  u32 padding_idc;
  s8 padding_word;
  u32 padding_size;
  u32 op_type;
  u32 conv_detail;
  u32 ifm_start_L;
  u32 ifm_start_m;
  u32 ifm_offset;
  u32 knl_start_L;
  u32 knl_start_m;
  u32 knl_offset;
  u32 knl_size;
  u32 ofm_bias_start_L;
  u32 ofm_bias_start_m;
  u32 ofm_start_L;
  u32 ofm_start_m;
  u32 ofm_offset;
  s32 out_shift;
  u32 lut_bypass;
  u32 ifm_sub_width;
  u32 ofm_sub_width_flag;
  u32 ofm_sub_width;
  Lut *lut_port;
  void Run();
  ~ConvPath();

private:
  s8 *OutBuffer;
  void DoConv(s8 *ifm_start, s8 *knl_start, s8 *bias_start, s8 *ofm_start, u32 knl_w);
  void DoFC(s8 *ifm_start, s8 *knl_start, s8 *bias_start, s8 *ofm_start);
  std::shared_ptr<MemInterface> InMemPtr;
  std::shared_ptr<MemInterface> OutMemPtr;
};

class Lut {
public:
  Lut();
  u32 lut_le_entry_num;
  u32 lut_lo_entry_num;
  u32 lut_init_wr_en;
  u32 lut_init_table_id;
  u32 lut_init_addr;
  u32 lut_init_data;
  u32 lut_le_start;
  u32 lut_le_end;
  u32 lut_le_index_select;
  u32 lut_le_slope_uflow_scale;
  u32 lut_le_slope_oflow_scale;
  u32 lut_le_slope_uflow_shift;
  u32 lut_le_slope_oflow_shift;
  u32 lut_lo_start;
  u32 lut_lo_end;
  u32 lut_lo_index_select;
  u32 lut_lo_slope_uflow_scale;
  u32 lut_lo_slope_oflow_scale;
  u32 lut_lo_slope_uflow_shift;
  u32 lut_lo_slope_oflow_shift;
  u32 lut_uflow_priority;
  u32 lut_oflow_priority;
  u32 lut_hybrid_priority;
  s32 query(s32 input);
  ~Lut();

private:
};

#endif
